package com.zenithmind.exam.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.exam.mapper.AnswerRecordMapper;
import com.zenithmind.exam.mapper.ExamMapper;
import com.zenithmind.exam.mapper.ExamRecordMapper;
import com.zenithmind.exam.mapper.QuestionMapper;
import com.zenithmind.exam.pojo.dto.AnswerSubmitDTO;
import com.zenithmind.exam.pojo.entity.*;
import com.zenithmind.exam.pojo.vo.ExamRecordVO;
import com.zenithmind.exam.service.ExamRecordService;
import com.zenithmind.exam.service.WrongQuestionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 考试记录服务实现类
 * 
 * @author ZenithMind
 * @since 2024-07-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExamRecordServiceImpl extends ServiceImpl<ExamRecordMapper, ExamRecord> implements ExamRecordService {

    private final ExamRecordMapper examRecordMapper;
    private final AnswerRecordMapper answerRecordMapper;
    private final ExamMapper examMapper;
    private final QuestionMapper questionMapper;
    private final WrongQuestionService wrongQuestionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startExam(String examId, String userId, String userName, String ipAddress, String userAgent) {
        try {
            // 检查是否已经有考试记录
            ExamRecord existingRecord = examRecordMapper.selectByExamIdAndUserId(examId, userId);
            if (existingRecord != null) {
                if (existingRecord.getStatus() == 1) {
                    // 如果是进行中状态，返回现有记录ID
                    return existingRecord.getId();
                } else if (existingRecord.getStatus() >= 2) {
                    throw new BusinessException("您已经参加过此考试");
                }
            }

            // 获取考试信息
            Exam exam = examMapper.selectById(examId);
            if (exam == null) {
                throw new BusinessException("考试不存在");
            }

            // 检查考试状态和时间
            LocalDateTime now = LocalDateTime.now();
            if (exam.getStatus() != 1 && exam.getStatus() != 2) {
                throw new BusinessException("考试未开始或已结束");
            }
            if (exam.getStartTime() != null && now.isBefore(exam.getStartTime())) {
                throw new BusinessException("考试尚未开始");
            }
            if (exam.getEndTime() != null && now.isAfter(exam.getEndTime())) {
                throw new BusinessException("考试已结束");
            }

            // 创建考试记录
            ExamRecord examRecord = new ExamRecord();
            examRecord.setExamId(examId);
            examRecord.setUserId(userId);
            examRecord.setUserName(userName);
            examRecord.setStatus(1); // 进行中
            examRecord.setStartTime(now);
            examRecord.setTotalScore(exam.getTotalScore());
            examRecord.setUserScore(BigDecimal.ZERO);
            examRecord.setCorrectCount(0);
            examRecord.setWrongCount(0);
            examRecord.setUnansweredCount(exam.getQuestionCount());
            examRecord.setIsPassed(0);
            examRecord.setIpAddress(ipAddress);
            examRecord.setUserAgent(userAgent);
            examRecord.setCreateTime(now);

            boolean result = save(examRecord);
            if (result) {
                // 更新考试参与人数
                examMapper.incrementParticipantCount(examId);
                log.info("开始考试成功，考试ID: {}, 用户ID: {}, 记录ID: {}", examId, userId, examRecord.getId());
            }
            
            return examRecord.getId();
        } catch (Exception e) {
            log.error("开始考试失败", e);
            throw new BusinessException("开始考试失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitAnswers(AnswerSubmitDTO answerSubmitDTO) {
        try {
            ExamRecord examRecord = getById(answerSubmitDTO.getExamRecordId());
            if (examRecord == null) {
                throw new BusinessException("考试记录不存在");
            }

            if (examRecord.getStatus() != 1) {
                throw new BusinessException("考试已结束，无法提交答案");
            }

            // 保存答题记录
            List<AnswerRecord> answerRecords = answerSubmitDTO.getAnswers().stream()
                    .map(questionAnswerDTO -> {
                        AnswerRecord answerRecord = new AnswerRecord();
                        answerRecord.setExamRecordId(answerSubmitDTO.getExamRecordId());
                        answerRecord.setQuestionId(questionAnswerDTO.getQuestionId());
                        answerRecord.setUserAnswer(JSON.toJSONString(questionAnswerDTO.getUserAnswer()));
                        answerRecord.setTimeSpent(questionAnswerDTO.getTimeSpent());
                        answerRecord.setAnswerTime(LocalDateTime.now());
                        return answerRecord;
                    })
                    .collect(Collectors.toList());

            // 批量插入答题记录
            answerRecordMapper.batchInsert(answerRecords);

            log.info("提交答案成功，考试记录ID: {}, 答题数量: {}", answerSubmitDTO.getExamRecordId(), answerRecords.size());
            return true;
        } catch (Exception e) {
            log.error("提交答案失败", e);
            throw new BusinessException("提交答案失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean finishExam(String examRecordId) {
        try {
            ExamRecord examRecord = getById(examRecordId);
            if (examRecord == null) {
                throw new BusinessException("考试记录不存在");
            }

            if (examRecord.getStatus() != 1) {
                throw new BusinessException("考试已结束");
            }

            // 计算考试用时
            LocalDateTime now = LocalDateTime.now();
            int durationSeconds = (int) ChronoUnit.SECONDS.between(examRecord.getStartTime(), now);

            // 更新考试记录状态
            examRecord.setStatus(2); // 已提交
            examRecord.setSubmitTime(now);
            examRecord.setDurationSeconds(durationSeconds);

            // 自动评分
            autoGradeExam(examRecord);

            boolean result = updateById(examRecord);
            if (result) {
                // 更新考试提交人数
                examMapper.incrementSubmittedCount(examRecord.getExamId());
                log.info("完成考试成功，考试记录ID: {}", examRecordId);
            }

            return result;
        } catch (Exception e) {
            log.error("完成考试失败", e);
            throw new BusinessException("完成考试失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean autoSubmitTimeoutExam(String examRecordId) {
        try {
            ExamRecord examRecord = getById(examRecordId);
            if (examRecord == null || examRecord.getStatus() != 1) {
                return false;
            }

            // 标记为超时提交
            examRecord.setStatus(4); // 已超时
            examRecord.setSubmitTime(LocalDateTime.now());

            // 计算实际用时
            int durationSeconds = (int) ChronoUnit.SECONDS.between(examRecord.getStartTime(), examRecord.getSubmitTime());
            examRecord.setDurationSeconds(durationSeconds);

            // 自动评分
            autoGradeExam(examRecord);

            boolean result = updateById(examRecord);
            if (result) {
                examMapper.incrementSubmittedCount(examRecord.getExamId());
                log.info("自动提交超时考试成功，考试记录ID: {}", examRecordId);
            }

            return result;
        } catch (Exception e) {
            log.error("自动提交超时考试失败", e);
            return false;
        }
    }

    @Override
    public ExamRecordVO getExamRecordById(String examRecordId) {
        ExamRecord examRecord = getById(examRecordId);
        if (examRecord == null) {
            return null;
        }
        return convertToVO(examRecord);
    }

    @Override
    public List<ExamRecordVO> getExamRecordsByExamId(String examId) {
        List<ExamRecord> records = examRecordMapper.selectByExamId(examId);
        return records.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<ExamRecordVO> getExamRecordsByUserId(String userId) {
        List<ExamRecord> records = examRecordMapper.selectByUserId(userId);
        return records.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public IPage<ExamRecordVO> getExamRecordPage(Page<ExamRecord> page, String examId, String userId, 
                                                String userName, Integer status) {
        IPage<ExamRecord> recordPage = examRecordMapper.selectRecordPage(page, examId, userId, userName, status);
        
        IPage<ExamRecordVO> voPage = new Page<>();
        BeanUtils.copyProperties(recordPage, voPage);
        
        List<ExamRecordVO> voList = recordPage.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        voPage.setRecords(voList);
        
        return voPage;
    }

    @Override
    public List<ExamRecordVO> getExamRanking(String examId, Integer limit) {
        List<ExamRecord> records = examRecordMapper.selectRanking(examId, limit);
        return records.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rescoreExamRecord(String examRecordId) {
        try {
            ExamRecord examRecord = getById(examRecordId);
            if (examRecord == null) {
                throw new BusinessException("考试记录不存在");
            }

            // 重新评分
            autoGradeExam(examRecord);
            
            boolean result = updateById(examRecord);
            if (result) {
                log.info("重新评分成功，考试记录ID: {}", examRecordId);
            }
            return result;
        } catch (Exception e) {
            log.error("重新评分失败", e);
            throw new BusinessException("重新评分失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchRescoreExamRecords(String examId) {
        try {
            List<ExamRecord> records = examRecordMapper.selectByExamId(examId);
            int successCount = 0;
            
            for (ExamRecord record : records) {
                if (record.getStatus() >= 2) { // 已提交的记录
                    autoGradeExam(record);
                    if (updateById(record)) {
                        successCount++;
                    }
                }
            }
            
            log.info("批量重新评分完成，考试ID: {}, 成功数量: {}/{}", examId, successCount, records.size());
            return successCount > 0;
        } catch (Exception e) {
            log.error("批量重新评分失败", e);
            throw new BusinessException("批量重新评分失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteExamRecord(String examRecordId) {
        try {
            // 删除答题记录
            answerRecordMapper.deleteByExamRecordId(examRecordId);
            
            boolean result = removeById(examRecordId);
            if (result) {
                log.info("删除考试记录成功，记录ID: {}", examRecordId);
            }
            return result;
        } catch (Exception e) {
            log.error("删除考试记录失败", e);
            throw new BusinessException("删除考试记录失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteExamRecords(List<String> examRecordIds) {
        try {
            // 删除答题记录
            for (String recordId : examRecordIds) {
                answerRecordMapper.deleteByExamRecordId(recordId);
            }
            
            boolean result = removeByIds(examRecordIds);
            if (result) {
                log.info("批量删除考试记录成功，数量: {}", examRecordIds.size());
            }
            return result;
        } catch (Exception e) {
            log.error("批量删除考试记录失败", e);
            throw new BusinessException("批量删除考试记录失败: " + e.getMessage());
        }
    }

    @Override
    public boolean hasUserTakenExam(String examId, String userId) {
        ExamRecord record = examRecordMapper.selectByExamIdAndUserId(examId, userId);
        return record != null && record.getStatus() >= 2;
    }

    @Override
    public ExamRecordVO getUserExamRecord(String examId, String userId) {
        ExamRecord record = examRecordMapper.selectByExamIdAndUserId(examId, userId);
        return record != null ? convertToVO(record) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleTimeoutExams() {
        try {
            List<ExamRecord> timeoutRecords = examRecordMapper.selectTimeoutRecords();
            for (ExamRecord record : timeoutRecords) {
                autoSubmitTimeoutExam(record.getId());
            }
            log.info("处理超时考试完成，数量: {}", timeoutRecords.size());
        } catch (Exception e) {
            log.error("处理超时考试失败", e);
        }
    }

    @Override
    public ExamRecordVO getExamRecordStatistics(String examId) {
        // 实现考试记录统计逻辑
        try {
            ExamRecordVO statistics = new ExamRecordVO();

            // 获取考试记录统计数据
            Map<String, Object> stats = getExamStatistics(examId);

            // 设置统计信息到VO中
            // 注意：这里需要根据ExamRecordVO的实际字段来设置
            log.info("获取考试记录统计信息，考试ID: {}", examId);

            return statistics;
        } catch (Exception e) {
            log.error("获取考试记录统计信息失败", e);
            return new ExamRecordVO();
        }
    }

    @Override
    public Map<String, Object> getExamStatistics(String examId) {
        try {
            Map<String, Object> statistics = new HashMap<>();

            // 获取参与人数（所有考试记录）
            LambdaQueryWrapper<ExamRecord> participantQuery = new LambdaQueryWrapper<>();
            participantQuery.eq(ExamRecord::getExamId, examId);
            long participantCount = examRecordMapper.selectCount(participantQuery);

            // 获取提交人数（已完成的考试记录）
            LambdaQueryWrapper<ExamRecord> submittedQuery = new LambdaQueryWrapper<>();
            submittedQuery.eq(ExamRecord::getExamId, examId)
                         .eq(ExamRecord::getStatus, 2); // 2表示已完成
            long submittedCount = examRecordMapper.selectCount(submittedQuery);

            // 获取分数统计（只统计已完成的记录）
            List<ExamRecord> completedRecords = examRecordMapper.selectList(submittedQuery);

            BigDecimal avgScore = BigDecimal.ZERO;
            BigDecimal maxScore = BigDecimal.ZERO;
            BigDecimal minScore = BigDecimal.ZERO;
            BigDecimal passRate = BigDecimal.ZERO;

            if (!completedRecords.isEmpty()) {
                // 计算平均分
                double avg = completedRecords.stream()
                        .mapToDouble(record -> record.getUserScore() != null ? record.getUserScore().doubleValue() : 0.0)
                        .average()
                        .orElse(0.0);
                avgScore = BigDecimal.valueOf(avg).setScale(2, RoundingMode.HALF_UP);

                // 计算最高分和最低分
                maxScore = completedRecords.stream()
                        .map(ExamRecord::getUserScore)
                        .filter(score -> score != null)
                        .max(BigDecimal::compareTo)
                        .orElse(BigDecimal.ZERO);

                minScore = completedRecords.stream()
                        .map(ExamRecord::getUserScore)
                        .filter(score -> score != null)
                        .min(BigDecimal::compareTo)
                        .orElse(BigDecimal.ZERO);

                // 计算通过率（需要获取考试的及格分数）
                // 这里简化处理，假设60分及格
                long passCount = completedRecords.stream()
                        .mapToLong(record -> {
                            BigDecimal score = record.getUserScore();
                            return (score != null && score.compareTo(BigDecimal.valueOf(60)) >= 0) ? 1 : 0;
                        })
                        .sum();

                if (submittedCount > 0) {
                    passRate = BigDecimal.valueOf(passCount)
                            .divide(BigDecimal.valueOf(submittedCount), 4, RoundingMode.HALF_UP)
                            .multiply(BigDecimal.valueOf(100))
                            .setScale(2, RoundingMode.HALF_UP);
                }
            }

            statistics.put("participantCount", participantCount);
            statistics.put("submittedCount", submittedCount);
            statistics.put("avgScore", avgScore);
            statistics.put("maxScore", maxScore);
            statistics.put("minScore", minScore);
            statistics.put("passRate", passRate);

            log.info("获取考试统计信息，考试ID: {}, 参与人数: {}, 提交人数: {}, 平均分: {}",
                    examId, participantCount, submittedCount, avgScore);

            return statistics;
        } catch (Exception e) {
            log.error("获取考试统计信息失败", e);
            throw new BusinessException("获取考试统计信息失败: " + e.getMessage());
        }
    }

    @Override
    public List<ExamRecordVO> exportExamRecords(String examId) {
        List<ExamRecord> records = examRecordMapper.selectByExamId(examId);
        return records.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    /**
     * 自动评分
     */
    private void autoGradeExam(ExamRecord examRecord) {
        List<AnswerRecord> answerRecords = answerRecordMapper.selectByExamRecordId(examRecord.getId());
        
        BigDecimal totalScore = BigDecimal.ZERO;
        int correctCount = 0;
        int wrongCount = 0;
        int unansweredCount = 0;

        for (AnswerRecord answerRecord : answerRecords) {
            Question question = questionMapper.selectById(answerRecord.getQuestionId());
            if (question == null) continue;

            List<String> userAnswers = JSON.parseArray(answerRecord.getUserAnswer(), String.class);
            List<String> correctAnswers = JSON.parseArray(question.getCorrectAnswer(), String.class);

            // 判断答案是否正确
            boolean isCorrect = isAnswerCorrect(userAnswers, correctAnswers, question.getType());
            
            if (userAnswers == null || userAnswers.isEmpty()) {
                // 未答题
                answerRecord.setIsCorrect(2);
                answerRecord.setUserScore(BigDecimal.ZERO);
                unansweredCount++;
            } else if (isCorrect) {
                // 答对了
                answerRecord.setIsCorrect(1);
                answerRecord.setUserScore(new BigDecimal(question.getScore()));
                totalScore = totalScore.add(new BigDecimal(question.getScore()));
                correctCount++;
                
                // 更新题目统计
                questionMapper.incrementUseCount(question.getId());
                questionMapper.incrementCorrectCount(question.getId());
            } else {
                // 答错了
                answerRecord.setIsCorrect(0);
                answerRecord.setUserScore(BigDecimal.ZERO);
                wrongCount++;
                
                // 添加到错题本
                wrongQuestionService.addWrongQuestion(examRecord.getUserId(), question.getId(), examRecord.getId());
                
                // 更新题目统计
                questionMapper.incrementUseCount(question.getId());
            }
            
            // 更新答题记录
            answerRecordMapper.updateById(answerRecord);
        }

        // 更新考试记录
        examRecord.setUserScore(totalScore);
        examRecord.setCorrectCount(correctCount);
        examRecord.setWrongCount(wrongCount);
        examRecord.setUnansweredCount(unansweredCount);
        
        // 判断是否及格
        Exam exam = examMapper.selectById(examRecord.getExamId());
        if (exam != null && exam.getPassScore() != null) {
            examRecord.setIsPassed(totalScore.compareTo(new BigDecimal(exam.getPassScore())) >= 0 ? 1 : 0);
        }
        
        examRecord.setStatus(3); // 已评分
    }

    /**
     * 判断答案是否正确
     */
    private boolean isAnswerCorrect(List<String> userAnswers, List<String> correctAnswers, Integer questionType) {
        if (userAnswers == null || userAnswers.isEmpty() || correctAnswers == null || correctAnswers.isEmpty()) {
            return false;
        }

        switch (questionType) {
            case 1: // 单选题
            case 5: // 判断题
                return userAnswers.size() == 1 && correctAnswers.contains(userAnswers.get(0));
            case 2: // 多选题
                return userAnswers.size() == correctAnswers.size() && 
                       userAnswers.containsAll(correctAnswers) && 
                       correctAnswers.containsAll(userAnswers);
            case 3: // 填空题
            case 4: // 简答题
                // 简单的字符串匹配，实际应用中可能需要更复杂的匹配逻辑
                return correctAnswers.stream().anyMatch(correct -> 
                    userAnswers.stream().anyMatch(user -> 
                        user.trim().equalsIgnoreCase(correct.trim())));
            default:
                return false;
        }
    }

    /**
     * 转换为VO对象
     */
    private ExamRecordVO convertToVO(ExamRecord examRecord) {
        ExamRecordVO vo = new ExamRecordVO();
        BeanUtils.copyProperties(examRecord, vo);
        
        // 设置状态名称
        vo.setStatusName(getStatusName(examRecord.getStatus()));
        
        // 格式化用时
        if (examRecord.getDurationSeconds() != null) {
            vo.setDurationFormatted(formatDuration(examRecord.getDurationSeconds()));
        }
        
        // 计算得分率
        if (examRecord.getTotalScore() != null && examRecord.getTotalScore() > 0) {
            BigDecimal scoreRate = examRecord.getUserScore()
                    .divide(new BigDecimal(examRecord.getTotalScore()), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100));
            vo.setScoreRate(scoreRate);
        }
        
        return vo;
    }

    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        switch (status) {
            case 0: return "未开始";
            case 1: return "进行中";
            case 2: return "已提交";
            case 3: return "已评分";
            case 4: return "已超时";
            default: return "未知";
        }
    }

    /**
     * 格式化时长
     */
    private String formatDuration(Integer seconds) {
        int hours = seconds / 3600;
        int minutes = (seconds % 3600) / 60;
        int secs = seconds % 60;
        
        if (hours > 0) {
            return String.format("%d小时%d分钟%d秒", hours, minutes, secs);
        } else if (minutes > 0) {
            return String.format("%d分钟%d秒", minutes, secs);
        } else {
            return String.format("%d秒", secs);
        }
    }
}
